/*
 *  cpu_console/cpu_console.c
 *  
 *              CPU Monitor 
 *
 *    Spring Semester.  044800.    Technion.
 *   Copyright (C) 2006  Evgeny Shulman  and Elizabeth Shtrom 
 */
 
 
 
#include <stdio.h>
#include <stdlib.h>

#include <linux/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>

#include "cpu_console.h"


int check_tss (int fd){
	cm_tss_struct tss_table;
	if ( read_tss(fd,&tss_table) )
		 return -1;
	display_tss( &tss_table);

	
	return 0;
}

int check_gdt (int fd, int sel, int count){
	cm_desc_t gdt_table[GDT_ENTRIES];
	if ( read_gdt(fd,gdt_table) )
		 return -1;
	display_gdt( gdt_table, sel, count) ;
	return 0;
}

int check_regs (int fd){
	regs_s all_regs;
	
	if ( read_regs(fd,&all_regs) )
		 return -1;
	display_regs(&all_regs );
	return 0;
}




int check_idt (int fd, int vec, int count) {
	cm_gate_desc_t idt_table[IDT_ENTRIES];
	if ( read_idt(fd,idt_table) )
		 return -1;
	display_idt( idt_table, vec, count) ;
	return 0;
}

int check_ldt (int fd, int sel, int count) {
	int ret;
	cm_desc_t ldt_table[LDT_ENTRIES];
	ret = read_ldt(fd,ldt_table) ;
	if ( ret == 0){
		display_ldt( ldt_table, sel, count) ;
		return 0;
	}else if ( ret == NO_LDT ) {
		fprintf(stderr, "ioctl : no LDT in the system \n" ) ; 
		return -1;
	}else{
		fprintf(stderr,  "ioctl error %d ", ret ) ;
		return -1;
	}	
	return 0 ;
	
}


int check_cpuid ( int fd ){
	display_cpuid(fd);
	return 0 ;
}


int check_im_start(int fd){
	PDEBUG_DISP("IDT MONITOR: started.\n");
	return im_start(fd);
}

int check_im_read (int fd){
	return check_im_read_smp ( &fd, 1) ;
}


int check_im_read_smp (int fd[], int cpu_to_display){
	int ret, i , cpu, isDisplay, total;
	im_irq_stat_s im_irq_stat_data[MAXnrCPUs];
	for ( cpu = 0 ; cpu  < cpu_to_display; cpu ++ ) {
		ret = im_read(fd[cpu], im_irq_stat_data+cpu );
		if (ret )
		{
			fprintf(stderr, "check_im_read : failed to read stats for cpu %d ret= %d fd= %d\n" , cpu, ret,fd[cpu] ) ; 
		    return ret;
		}
	}
	
	PDEBUG_DISP("\n---------------IDT MONITOR---------------\n");
	PDEBUG_DISP("<<<INT>>>> ");
	for ( cpu = 0 ; cpu  < cpu_to_display; cpu ++ ) {
		PDEBUG_DISP ("       cpu<%d>      ", cpu) ;
	}
	PDEBUG_DISP ("\n");
	total = 0;
	for ( i =  0 ; i <IDT_ENTRIES ; i ++){
		isDisplay  = 0;
		for ( cpu = 0 ; cpu  < cpu_to_display; cpu ++ ) {
			isDisplay += im_irq_stat_data[cpu].irqs[i];
		}
		
		if (isDisplay){
			PDEBUG_DISP ("0x%2.2x(%3d) ", i,i);
			for ( cpu = 0 ; cpu  < cpu_to_display; cpu ++ ) {
				total += im_irq_stat_data[cpu].irqs[i];
				PDEBUG_DISP ("        %d        ", im_irq_stat_data[cpu].irqs[i]) ;
			}
			PDEBUG_DISP ("\n");
		}
	} 
	PDEBUG_DISP ("-----------\n total = %d \n\n", total);
	return 0;
}

	

int check_im_stop (int fd){
	PDEBUG_DISP("IDT MONITOR: stopped.\n");
	return im_stop(fd);
}





int check_im_smp(int fd [],int cpu_to_process, int idt_start, int idt_count, int times){
	int boot_fd, i ;
	boot_fd = fd[0];
	
	check_idt(     boot_fd,idt_start,idt_count);
	check_im_start(boot_fd);
	check_idt(     boot_fd,idt_start,idt_count);
	
	sleep(1);
	for ( i = 0 ; i < times; i ++ ) {
		PDEBUG_DISP("READ %d\n", i );
		check_im_read_smp (fd, cpu_to_process);
		sleep (2);
	}
			
	check_im_stop (boot_fd);
	check_idt(     boot_fd,idt_start,idt_count);
	
	
	return 0;
}







int check_pgd_and_pt (int fd,int index , int count,int entry){
	unsigned long  pgd_entry =0 ,pgd_table[PGD_TABLE_ENTRIES];
	int ret;
	PDEBUG("check_pgd_and_pt: index  = %d entry = %d \n", index, entry);
	
	if ( ! CHECK_INDEX(index,PT_TABLE_ENTRIES) ) 	 return -INDEX_INVALID;
	PDEBUG("check_pgd_and_pt: read.\n");
	
	if ( ( entry >= 0  )&&  (! CHECK_INDEX( (entry),PT_TABLE_ENTRIES) ) )	 return -INDEX_INVALID;

	FIX_COUNTER( index, count, USER_ENTRIES, PT_TABLE_ENTRIES);

	
	ret = read_pgd( fd ,  pgd_table ) ;
	if (ret){
		fprintf(stderr, "check_pgd_and_pt: read_ptable failed! ret=%d\n", ret); 
		return -1;
	}
	
	if       ( entry == -1 ) {
		PDEBUG("check_pgd_and_pt: display.\n");
		display_pgdir( pgd_table , index ,  count);
		return 0;
	}else if ( entry == -2 ) {
		PDEBUG("check_pgd_and_pt: display.\n");
		display_pgdir( pgd_table , index ,  count);
		pgd_entry = check_pt_first_present ( pgd_table);
	}else if ( entry >=  0 )  {
	    pgd_entry =  *( pgd_table + entry );
 	}
 	
	
	if ( pgd_entry ) {
		PDEBUG_DISP( "Displaying PT table for PGD ENTRY = 0x%08lx\n", pgd_entry );
		check_pt( fd, pgd_entry, index ,count);
	}else{
		fprintf(stderr, "check_pgd_and_pt: pde_entry not valid for entry = %d\n", entry); 
	}	
	return 0;
}

int check_pt (int fd,unsigned long pgd_entry,int index , int count ){
	int ret;
	unsigned long pt_table[PT_TABLE_ENTRIES];
	if (   ( !(pgd_entry  & 0x1)) || (pgd_entry & 0x80 ) )  {
		fprintf(stderr, "check_pt: wrong pgd_entry=0x%08lx  - not present\n",pgd_entry); 
		return -1;
	}
	
	ret= read_ptable ( fd , pgd_entry , pt_table );
	if (ret){
		fprintf(stderr, "check_pt: read_ptable failed! ret=%d\n", ret); 
		return -1;
	}
	display_ptable( pt_table , index ,  count );
	return 0;
}


unsigned long check_pt_first_present ( unsigned long* pgd_table){
	int i;
	unsigned long *pgd_entry;
	for ( i=0, pgd_entry = pgd_table ;i<PGD_TABLE_ENTRIES;i++, pgd_entry++){
 		if ((*pgd_entry  & 0x1) && !( *pgd_entry & 0x80 )) {
			PDEBUG_DISP("pde present index %d = 0x%08lx \n",i, *pgd_entry);	
			return *pgd_entry;
		}
	}
	return 0;
}





